package com.objk.admin.security.config;

import com.google.common.collect.Lists;
import com.objk.admin.security.component.Md5PasswordEncoder;
import com.objk.admin.security.filter.CustomAccessDecisionManager;
import com.objk.admin.security.filter.ValidateCodeConfig;
import com.objk.admin.security.hander.CustomAccessDeniedHandler;
import com.objk.admin.security.hander.LoginFailureHandler;
import com.objk.admin.security.hander.LoginSuccessHandler;
import com.objk.admin.security.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.session.data.redis.RedisOperationsSessionRepository;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.session.security.SpringSessionBackedSessionRegistry;

import java.util.List;


/**
 * security安全配置
 *
 * @author yuan 2019/6/19 13:24
 */
@Configuration
@EnableWebSecurity
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800)
public class WebSercurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private LoginSuccessHandler loginSuccessHandler;

    @Autowired
    private LoginFailureHandler loginFailureHandler;

    @Autowired
    private Md5PasswordEncoder md5PasswordEncoder;

    @Autowired
    private IUserService userService;

    @Autowired
    private RedisTemplate redisTemplate;

   /* @Autowired
    private CustomAccessDecisionManager customAccessDecisionManager;*/

    //@Autowired
    //private CustomFilterInvocationSecurityMetadataSource customFilterInvocationSecurityMetadataSource;

    @Autowired
    private CustomAccessDeniedHandler customAccessDeniedHandler;

    @Autowired
    private ValidateCodeConfig validateCodeConfig;

    private HttpSecurity httpSecurity;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(this.userService).passwordEncoder(this.md5PasswordEncoder);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.
                headers().frameOptions().disable().and()
                // 禁用缓存
                .headers().cacheControl().and().and()
                // 防止csrf攻击
                .csrf().disable()
                .authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                // 不需要认证请求
                .antMatchers(WebSercurityConfig.noAuthRequiredResource()).permitAll().and()
                // 所有请求都需要认证
                .authorizeRequests().anyRequest()
                .authenticated().and()
                .formLogin()
                // 自定义登录页面路径
                .loginPage("/admin/login.html")
                // 自定义登录请求路径
                .successForwardUrl("/admin/index")
                .loginProcessingUrl("/admin/login")
                // 登录成功的处理器
                .successHandler(loginSuccessHandler)
                // 登录失败的处理器
                .failureHandler(loginFailureHandler).and()
                // 自定义退出登录的路径
                .logout().logoutUrl("/admin/logout").deleteCookies("JSESSIONID")
                // 退出成功后的跳转路径
                .logoutSuccessUrl("/admin/login.html").and();

        http.sessionManagement().maximumSessions(1).sessionRegistry(sessionRegistry()).maxSessionsPreventsLogin(false).expiredUrl("/admin/expire.html");
        //http.authorizeRequests().withObjectPostProcessor(objectPostProcessor()).and();
        //校验是否有权限
        http.authorizeRequests().anyRequest()
                .access("@permissionService.hasPermission(request,authentication)");
        http.exceptionHandling().accessDeniedHandler(this.customAccessDeniedHandler);
        // 图片验证码配置
        http.apply(validateCodeConfig);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        /**
         * 不过滤前端资源
         **/
        web.ignoring().antMatchers(HttpMethod.GET,
                "/**/*.js",
                "/**/*.css",
                "/**/*.uijs",
                "/**/*.uicss",
                "/**/*.woff2*",
                "/**/*.woff*",
                "/**/*.ttf*",
                "/**/*.png",
                "/**/*.gif",
                "/**/*.jpg",
                "/**/*.mp3",
                "/**/*.css.map",
                "/**/*.js.map",
                "/uiengine.uijs",
                "/uiengine.uicss",
                "/**/*.ico",
                "/v2/api-docs",
                "/swagger/**",
                "/v2/api-docs",
                "/swagger-resources/**",
                "/swagger/**",
                "/actuator/**"
        );
    }

    public static String[] noAuthRequiredResource() {
        List<String> noAuthRequires = Lists.newArrayList(
                "/common/**",
                "/captcha/**",
                "/404.html",
                "/403.html",
                "/admin/login.html"
        );

        String[] antResources = new String[noAuthRequires.size()];
        return noAuthRequires.toArray(antResources);
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }

    /**
     * 使用redis存储session信息
     */
    @Bean
    public SpringSessionBackedSessionRegistry sessionRegistry() {
        RedisOperationsSessionRepository redisOperationsSessionRepository = new RedisOperationsSessionRepository(redisTemplate);
        return new SpringSessionBackedSessionRegistry(redisOperationsSessionRepository);
    }

    /*public ObjectPostProcessor<FilterSecurityInterceptor> objectPostProcessor() {
        return new ObjectPostProcessor<FilterSecurityInterceptor>() {
            @Override
            public <O extends FilterSecurityInterceptor> O postProcess(O fsi) {
                fsi.setAccessDecisionManager(customAccessDecisionManager);
                fsi.setSecurityMetadataSource(customFilterInvocationSecurityMetadataSource);
                return fsi;
            }
        };
    }*/

}
